<!--
 * @Description:会动的词云
 * @Author: Vergil
 * @Date: 2021-08-25 14:17:45
 * @LastEditTime: 2021-08-25 17:08:15
 * @LastEditors: Vergil
-->
<template>
  <div ref="wordCloud" class="wordCloud" />
</template>
<script>
export default {
  name: 'WordCloud',
  data() {
    return {
      hotWord: ['万事如意', '事事如意 ', '万事亨通', '一帆风顺', '万事大吉', '吉祥如意', '步步高升', '步步登高', '三羊开泰', '得心应手', '财源广进', '陶未媲美', '阖家安康', '龙马精神', '锦绣前程', '吉祥如意', '生龙活虎', '神采奕奕', '五谷丰登', '马到成功', '飞黄腾达', ' 步步高升', '福禄寿禧'],
      color: [
        '#a18cd1', '#fad0c4', '#ff8177',
        '#fecfef', '#fda085', '#f5576c',
        '#fe9a8b', '#30cfd0', '#38f9d7'
      ],
      wordArr: [],
      timer: null,
      resetTime: 10,
      ContainerSize: ''
    }
  },
  mounted() {
    this.init()
  },
  destroyed() {
    // 组件销毁，关闭定时执行
    cancelAnimationFrame(this.timer)
  },
  methods: {
    init() {
      this.dealSpan()
      this.initWordPos()
      this.render()
    },
    dealSpan() {
      const wordArr = []
      this.hotWord.forEach((value) => {
        // 根据词云数量生成span数量设置字体颜色和大小
        const spanDom = document.createElement('span')
        spanDom.style.position = 'relative'
        spanDom.style.display = 'inline-block'
        spanDom.style.color = this.randomColor()
        spanDom.style.fontSize = this.randomNumber(15, 30) + 'px'
        spanDom.innerHTML = value
        spanDom.local = {
          position: {
            // 位置
            x: 0,
            y: 0
          },
          direction: {
            // 方向 正数往右 负数往左
            x: 1,
            y: 1
          },
          velocity: {
            // 每次位移初速度
            x: -0.5 + Math.random(),
            y: -0.5 + Math.random()
          }
        }
        this.$refs.wordCloud.appendChild(spanDom)
        wordArr.push(spanDom)
      })
      this.wordArr = wordArr
    },
    randomColor() {
      // 获取随机颜色
      var colorIndex = Math.floor(this.color.length * Math.random())
      return this.color[colorIndex]
    },
    randomNumber(lowerInteger, upperInteger) {
      // 获得一个包含最小值和最大值之间的随机数。
      const choices = upperInteger - lowerInteger + 1
      return Math.floor(Math.random() * choices + lowerInteger)
    },
    render() {
      if (this.resetTime < 100) {
        this.resetTime = this.resetTime + 1
        this.timer = requestAnimationFrame(this.render.bind(this))
        this.resetTime = 0
      }
      this.wordFly()
    },
    wordFly() {
      this.wordArr.forEach((value) => {
        // 设置运动方向 大于边界或者小于边界的时候换方向
        if (value.local.realPos.minx + value.local.position.x < this.ContainerSize.leftPos.x || value.local.realPos.maxx + value.local.position.x > this.ContainerSize.rightPos.x) value.local.direction.x = -value.local.direction.x
        if (value.local.realPos.miny + value.local.position.y < this.ContainerSize.leftPos.y || value.local.realPos.maxy + value.local.position.y > this.ContainerSize.rightPos.y) value.local.direction.y = -value.local.direction.y
        value.local.position.x += value.local.velocity.x * value.local.direction.x
        value.local.position.y += value.local.velocity.y * value.local.direction.y
        // 给每个词云加动画过渡
        value.style.transform = 'translateX(' + value.local.position.x + 'px) translateY(' + value.local.position.y + 'px)'
      })
    },
    initWordPos() {
      // 计算每个词的真实位置和容器的位置
      this.wordArr.forEach((value) => {
        value.local.realPos = {
          minx: value.offsetLeft,
          maxx: value.offsetLeft + value.offsetWidth,
          miny: value.offsetTop,
          maxy: value.offsetTop + value.offsetHeight
        }
      })
      this.ContainerSize = this.getContainerSize()
    },
    getContainerSize() {
      // 判断容器大小控制词云位置
      const el = this.$refs.wordCloud
      return {
        leftPos: {
          // 容器左侧的位置和顶部位置
          x: el.offsetLeft,
          y: el.offsetTop
        },
        rightPos: {
          // 容器右侧的位置和底部位置
          x: el.offsetLeft + el.offsetWidth,
          y: el.offsetTop + el.offsetHeight
        }
      }
    }
  }
}
</script>
<style lang="css" scoped>
.wordCloud{
   width:100%;
   height:100%;
}
</style>
